#ifndef _STM_ST7789H_
#define _STM_ST7789H_
#include "Arduino.h"
#include "Print.h"
#include <SPI.h>
#include "gfxfont.h"
#include <STMSPIDMA.h>
#define ST_CMD_DELAY 0x80 // special signifier for command lists
#define ST77XX_NOP 0x00
#define ST77XX_SWRESET 0x01
#define ST77XX_RDDID 0x04
#define ST77XX_RDDST 0x09
#define ST77XX_SLPIN 0x10
#define ST77XX_SLPOUT 0x11
#define ST77XX_PTLON 0x12
#define ST77XX_NORON 0x13
#define ST77XX_INVOFF 0x20
#define ST77XX_INVON 0x21
#define ST77XX_DISPOFF 0x28
#define ST77XX_DISPON 0x29
#define ST77XX_CASET 0x2A
#define ST77XX_RASET 0x2B
#define ST77XX_RAMWR 0x2C
#define ST77XX_RAMRD 0x2E
#define ST77XX_PTLAR 0x30
#define ST77XX_TEOFF 0x34
#define ST77XX_TEON 0x35
#define ST77XX_MADCTL 0x36
#define ST77XX_COLMOD 0x3A
#define ST77XX_WRDISBV 0x51  //亮度控制 0x00-0xff
#define ST77XX_MADCTL_MY 0x80
#define ST77XX_MADCTL_MX 0x40
#define ST77XX_MADCTL_MV 0x20
#define ST77XX_MADCTL_ML 0x10
#define ST77XX_MADCTL_RGB 0x00
#define ST77XX_RDID1 0xDA
#define ST77XX_RDID2 0xDB
#define ST77XX_RDID3 0xDC
#define ST77XX_RDID4 0xDD
// Some ready-made 16-bit ('565') color settings:
#define ST77XX_BLACK 0x0000 //黑色 0x167E//
#define ST77XX_WHITE 0xFFFF //白色
#define ST77XX_RED 0xF800   //红色
#define ST77XX_GREEN 0x07E0 //绿色
#define ST77XX_BLUE 0x001F  //蓝色
#define ST77XX_CYAN 0x07FF  //青色
#define ST77XX_MAGENTA 0xF81F//洋红色
#define ST77XX_YELLOW 0xFFE0  //黄色
#define ST77XX_ORANGE 0xFC00  //橙色
static const uint8_t PROGMEM
generic_st7789[] = {                // Init commands for 7789 screens
  9,                              //  9 commands in list:
  ST77XX_SWRESET,   ST_CMD_DELAY, //  1: 软件重置，无参数，带延迟
    150,                          //     ~150 ms delay
  ST77XX_SLPOUT ,   ST_CMD_DELAY, //  2: 脱离睡眠模式，无参数，带延迟
    10,                          //      10 ms delay
  ST77XX_COLMOD , 1 + ST_CMD_DELAY, //  3: 设置颜色模式，1 arg+延迟：
    0x55,                         //     16-bit color
    10,                           //     10 ms delay
  ST77XX_MADCTL , 1,              //  4: 记忆访问控制（方向），1参数：
    0x08,                         //     行/列地址，底部-顶部刷新
  ST77XX_CASET  , 4,              //  5: 列地址集，4个参数，无延迟：
    0x00,
    0,        //     XSTART = 0
    0,
    240,  //     XEND = 240
  ST77XX_RASET  , 4,              //  6: 行地址集，4个参数，无延迟：
    0x00,
    0,             //     YSTART = 0
    320 >> 8,
    320 & 0xFF,  //     YEND = 320
  ST77XX_INVON  ,   ST_CMD_DELAY,  //  7: hack
    10,
  ST77XX_NORON  ,   ST_CMD_DELAY, //  8: 正常显示打开，无参数，带延迟
    10,                           //     10 ms delay
  ST77XX_DISPON ,   ST_CMD_DELAY, //  9: 主屏幕打开，无参数，延迟
    10 };
class STM_ST7789 : public Print {
public:
  STM_ST7789(SPIDMAClass* spiClass, int8_t cs, int8_t dc, int8_t rst);
  void begin(uint16_t width, uint16_t height);//初始化
  void setRotation(uint8_t m);//设置旋转
  void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h); //设置显示区域
  void enableDisplay(boolean enable); //打开或关闭显示
  void enableTearing(boolean enable); //打开或关闭撕裂
  void enableSleep(boolean enable);   //启用睡眠
  void invertDisplay(bool i);         //颜色反转

  void drawPixel(int16_t x, int16_t y, uint16_t color);
  void drawarray(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* array);
  void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
  void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
  void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
  void drawRGBBitmap(int16_t x, int16_t y, uint16_t* pcolors, int16_t w, int16_t h);
  void writearray(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t* color);
  void fillScreen(uint16_t color);
  void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
  void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
  void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
  void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color);
  void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
  void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color);
  void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
  void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
  void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
  void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
  void drawChar(int16_t x, int16_t y, uint8_t c, uint16_t color, uint16_t bg);
  void drawmutant(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t* array, uint16_t number, uint16_t color, uint16_t bg);
  void drawpicture(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t* array);
  void setFont(const GFXfont* f = NULL);   //设置字体
  //设置文本光标位置
  void setCursor(int16_t x, int16_t y) {
    cursor_x = x;
    cursor_y = y;
  }
  //设置透明背景的文本字体颜色
  void setTextColor(uint16_t c) { textcolor = textbgcolor = c; }
  //使用自定义背景色设置文本字体颜色
  void setTextColor(uint16_t c, uint16_t bg) {
    textcolor = c;
    textbgcolor = bg;
  }
  //设置对于屏幕宽度来说太长的文本是否应自动换行到下一行（否则向右剪裁）。
  void setTextWrap(bool w) { wrap = w; }
  void cp437(bool x = true) { _cp437 = x; }
  uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
  

  using Print::write;
  virtual size_t write(uint8_t);



protected:
  uint8_t _colstart2 = 0, ///< 向右偏移
    _rowstart2 = 0;     ///< 从底部偏移
  uint8_t _colstart = 0,   ///< 某些显示器需要将其更改为偏移
    _rowstart = 0;    ///< 某些显示器需要将其更改为偏移
  SPIDMAClass* _spi; ///< SPI类指针                    
  uint8_t connection;      ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc.
  int8_t _rst;             ///< 复位引脚 # (or -1)
  int8_t _cs;              ///< 芯片选择引脚
  int8_t _dc;              ///< 数据/命令引脚 #
  int16_t _xstart = 0;          ///< 内部帧缓冲区X偏移
  int16_t _ystart = 0;          ///< 内部帧缓冲区Y偏移
  uint8_t invertOnCommand = 0;  ///< 启用反转模式的命令
  uint8_t invertOffCommand = 0; ///< 禁用反转模式的命令
  int16_t WIDTH;        ///< 这是“原始”显示宽度-从不更改
  int16_t HEIGHT;       ///< 这是“原始”显示宽度-从不更改
  int16_t _width;       ///< 显示由当前旋转修改的宽度
  int16_t _height;      ///< 显示由当前旋转修改的高度
  int16_t cursor_x;     ///< x 开始打印（）文本的位置
  int16_t cursor_y;     ///< y 开始打印（）文本的位置
  uint16_t textcolor;   ///< 16-bit print()的背景色
  uint16_t textbgcolor; ///< 16-bit print()的字体颜色
  uint8_t rotation;     ///< 显示旋转 (0 thru 3)
  bool wrap;            ///< 如果设置，则在显示的右边缘“换行”文本
  bool _cp437;          ///< 如果已设置，请使用正确的CP437字符集（默认为关闭）
  GFXfont* gfxFont;     ///< 指向特殊字体的指针
  uint8_t casualdate [4096]; //颜色数据暂存数组
  uint8_t writecount=0;
  uint8_t temparray[3];
  void displayInit(const uint8_t* addr);
  void setColRowStart(int8_t col, int8_t row);
  void SPI_DC_HIGH(void) {
    digitalWrite(_dc, HIGH);
  }
  void SPI_DC_LOW(void) {
    digitalWrite(_dc, LOW);
  }
  void SPI_BEGIN_TRANSACTION(void);
  void SPI_END_TRANSACTION(void);
  // 尽管进行了并行添加，但仍保留了函数名以保持兼容性：
  void spiWrite(uint8_t b);          // Write single byte as DATA
  void writeCommand(uint8_t cmd);    // Write single byte as COMMAND
  void write16(uint16_t w);          // Write 16-bit value as DATA
  void writeCommand16(uint16_t cmd); // Write 16-bit value as COMMAND
  void SPI_WRITE16(uint16_t w); // Not inline
  void SPI_WRITE32(uint32_t l); // Not inline
  void SPI_DMAARRAY(uint8_t* array, size_t _count);
  void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
  void writePixel(int16_t x, int16_t y, uint16_t color);//写入一个像素
  void writePixels(uint16_t* colors, uint32_t len);//写入一串像素
  void writeColor(uint16_t color, uint32_t len);
  void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
  void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
  void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
  void sendCommand(uint8_t commandByte, uint8_t* dataBytes, uint8_t numDataBytes);
  void sendCommand(uint8_t commandByte, const uint8_t* dataBytes = NULL, uint8_t numDataBytes = 0);
  void sendCommand16(uint16_t commandWord, const uint8_t* dataBytes = NULL, uint8_t numDataBytes = 0);
  virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
  //获取显示器的宽度，考虑当前旋转
  int16_t width(void) const { return _width; };
  //获取显示器的高度，计入当前旋转
  int16_t height(void) const { return _height; }
  //获取显示的旋转设置
  uint8_t getRotation(void) const { return rotation; }
  // 获取当前光标位置（获取旋转安全的最大值，使用：width（）表示x，height（）表示y）
  int16_t getCursorX(void) const { return cursor_x; }
  //获取文本光标Y位置
  int16_t getCursorY(void) const { return cursor_y; };
private:
  uint16_t windowWidth;
  uint16_t windowHeight;
};

#endif // _STM_ST7789H_
